package com.pocket.insight.base.sql.dataset;

import com.pocket.insight.base.mql.Relation;
import com.pocket.insight.base.sql.*;
import com.pocket.insight.base.mql.relation.PrimeRelation;
import com.pocket.insight.entity.Dataset;
import lombok.Data;
import org.apache.commons.collections4.CollectionUtils;

import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * 描述：
 *
 * @author shuize
 * @create 2024/12/4
 */
@Data
public class DatasetResource {

    private Vendor       vendor;
    private Dataset      dataset;
    private Long         effectiveStorageConnectionId;
    private Relation     datasetRelation;
    private List<Object> userExcludeColumns;

    public Relation getRelation() {
        return getRelation(null);
    }

    public Relation getRelation(List<Dataset.Field> fields) {
        if (this.datasetRelation != null) {
            this.datasetRelation.clearRunTime();
        }
        Relation relation = getDatasetRelation().setAlias(getTableAlias());
        if (CollectionUtils.isEmpty(fields)) {
            return relation;
        }

        SchemaProvider schemaProvider = getSchemaProvider();
        Map<String, Dataset.Field> thisMap = DatasetUtil.toSchemaMap(fields);
        Map<String, Dataset.Field> newMap = new LinkedHashMap<>();
        schemaProvider.getFields().forEach(field -> {
            if (thisMap.containsKey(field.getFieldName())) {
                Dataset.Field altField = getPreviewFieldForEngine(thisMap.get(field.getFieldName()), thisMap);
                newMap.put(altField.getFieldName(), altField);
            } else {
                newMap.put(field.getFieldName(), field);
            }
        });
        fields.forEach(field -> {
            if (!newMap.containsKey(field.getFieldName())) {
                Dataset.Field altField = getPreviewFieldForEngine(field, newMap);
                newMap.put(altField.getFieldName(), altField);
            }
        });
        if (relation instanceof PrimeRelation primeRelation && relation.getSchemaProvider() instanceof DatasetSchemaProvider) {
            Relation result = PrimeRelation.create(
                        primeRelation.getDialect(),
                        primeRelation.dataset,
                        new DatasetSchemaProvider(newMap, schemaProvider.fetchMetricMap())
                    ).setAlias(relation.getAlias())
                     .setRelationSize(relation.getRelationSize());
            result.getWith().addAll(relation.getWith());
            return result;
        }
        return relation;
    }

    public List<Dataset.Field> getSchema() {
        return this.dataset.getSchema();
    }

    public void setSchema(List<Dataset.Field> fields) {
        this.dataset.setSchema(fields);
    }

    public String getTableAlias() {
        return SqlEval.idToAlias(this.dataset == null ? null : this.dataset.getId());
    }


    public void setEffectiveStorageConnectionId(Long effectiveStorageConnectionId) {
        this.effectiveStorageConnectionId = effectiveStorageConnectionId;
    }

    public void setDatasetRelation(Relation datasetRelation) {
        this.datasetRelation = datasetRelation;
        if (datasetRelation.getRelationSize() == null) {
            datasetRelation.setRelationSize(this.dataset.getOptions().getRowCount());
        }
    }

    public SchemaProvider getSchemaProvider() {
        if (this.datasetRelation != null && this.datasetRelation.getSchemaProvider() != null){
            return this.datasetRelation.getSchemaProvider();
        }
        Map<String, Dataset.Field> originFieldsMap = this.getDataset().fetchSchemaMap();
        Map<String, Dataset.Field> schemaMap = new LinkedHashMap();
        CollectionUtils.emptyIfNull(this.getSchema()).forEach((field) -> {
            field.setDatasetId(this.dataset.getId());
            Dataset.Field altField = this.getPreviewFieldForEngine(field, originFieldsMap);
            schemaMap.put(altField.getFieldName(), altField);
        });
        return (CollectionUtils.isEmpty(this.getSchema()) ? BaseSchemaProvider.create() : SchemaProviderFactory.create(schemaMap, this.dataset.fetchMetricMap()));
    }


    private Dataset.Field getPreviewFieldForEngine(Dataset.Field field, Map<String, Dataset.Field> schemaMap) {
        if (field == null) {
            return null;
        } else {
            Dataset.Field altField = field.partialDeepCopy();
            return altField;
        }
    }

}
